package vin.pth.authorization.filter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.json.JacksonJsonParser;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import vin.pth.authorization.config.AuthorizationProperties;
import vin.pth.authorization.exception.AuthorizationException;
import vin.pth.authorization.handler.AuthorizationHandler;
import vin.pth.authorization.manager.AuthorizationManager;
import vin.pth.base.pojo.Authentication;

/**
 * 认证拦截器，用于拦截登陆请求和后续行为.
 *
 * @author cocoon
 */
@Slf4j
@RequiredArgsConstructor
public class AuthorizationFilter implements Filter {

  private final AuthorizationManager authorizationManager;
  private final AuthorizationHandler authorizationHandler;
  @Resource
  private AuthorizationProperties authorizationProperties;

  private boolean isLogin(HttpServletRequest request) {
    if (request.getMethod().equals(HttpMethod.POST.name())) {
      return StringUtils.pathEquals(authorizationProperties.getLoginUri(), request.getRequestURI());
    }
    return false;
  }


  /**
   * 进行认证.
   *
   * @param request [request]
   * @return 认证对象
   * @throws AuthorizationException 认证异常
   * @throws IOException            io异常
   */
  public Authentication attemptAuthentication(HttpServletRequest request)
      throws AuthorizationException, IOException {
    BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(),
        StandardCharsets.UTF_8));
    StringBuilder responseStrBuilder = new StringBuilder();
    String inputStr;
    while ((inputStr = streamReader.readLine()) != null) {
      responseStrBuilder.append(inputStr);
    }
    Map<String, Object> param =
        new JacksonJsonParser().parseMap(responseStrBuilder.toString());
    return authorizationManager.authenticate(param);
  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    if (!isLogin(httpServletRequest)) {
      chain.doFilter(request, response);
      return;
    }
    try {
      authorizationHandler.successHandle(httpServletRequest, httpServletResponse,
          attemptAuthentication(httpServletRequest));
    } catch (AuthorizationException e) {
      authorizationHandler.failureHandler(httpServletRequest, httpServletResponse, e);
    }
  }

}
